package com.company


fun main() {
    //----------------------------------------基本语法--------------
    //1、声明可修改变量  使用 var     声明只读变量  使用val
    val name: String = "zhangsan"
    println(name)

    var num: Int = 20
    num = 18
    println(num)

    //2、类型推断    对于已声明并赋值的变量，允许省略类型定义
    val str = "hello world"
    println(str)


    //3、编译时常量
    //只读变量并非绝对只读
    //编译时常量只能在函数之外定义。编译时常量必须在编译时赋值，而函数都是在运行时才调用
    //编译时常量只能是基本数据类型：String Int Double Float Long Short Byte Char Boolean

    //4、查看kotlin字节码
    // shift键两次输入show kotlin        tools-kotlin-show kotlin bytecode

    //5、kotlin只提供引用类型    而java有引用类型和基本数据类型


    //6、表达式
    //if/else if  range(in A..B)    when
    val age = 0
    if (age in 0..3) {
        println("婴幼儿")
    } else if (age in 3..12) {
        println("少儿")
    } else {
        println("未知")
    }

    //只要代码包含else if分支   都建议改用when表达式
    val school = "小学"
    val level = when (school) {
        "学前班" -> "幼儿"
        "小学" -> "少儿"
        "大学" -> "成年"
        else -> {
            println("未知")
        }
    }
    println(level)

    //7、String模板
    //模板支持在字符串的引号内放入变量值
    //支持字符串里计算表达式的值插入结果
    val orgin = "Jack"
    val dest = "Rose"
    println("$orgin love $dest")

    val flag = false
    println("Answer is : ${if (flag) "我可以" else "对不起"}")

    //8、函数
    fun doSome(name: String = "java", age: Int = 2): String {
        return "result is good"
    }
    // 如果使用命名值参，就可以不用管值参的顺序
    doSome(age = 4, name = "java")

    //9、Unit函数  kotlin中没有返回值的函数叫Unit函数  返回类型是Unit

    //10、Nothing类型  TODO函数 的任务就是抛出异常 返回Nothing类型

    //11、反引号中的函数名
    fun `**function with name**`() {
        //MyJava.`is`()  // 可以调用java方法
    }

    //12、匿名函数   可以定制标准库里的内置函数
    val total = "Mississippi".count()
    val totalS = "Mississippi".count({ letter -> letter == 's' })
    val totalS2 = "Mississippi".count { letter -> letter == 's' }
    println(total)
    println(totalS)
    println(totalS2)
    //如果一个函数的lambda参数排在最后或者是唯一的参数，圆括号可以省略
    "Mississippi".count({ it == 's' })
    "Mississippi".count { it == 's' }

    //13、匿名函数类型和隐士返回
    //变量的类型是一个匿名函数
    //变量有类型，可以等于函数      函数也有类型由传入的参数和返回值类型决定
    //匿名函数可以当做类型赋值给函数类型变量
    val blessingFunction: () -> String
    blessingFunction = {
        val holiday = "New Year"
        "Happy $holiday"
    }
//    println(blessingFunction)
    println(blessingFunction())

    //14、函数参数
    val blessingFunction2: (String) -> String = { name ->
        val holiday = "New Year"
        "$name ,Happy $holiday"
    }
    println(blessingFunction2("jack"))

    //15、it关键字  只用一个参数的匿名函数时，可以使用it关键字来表示参数名。两个参数就不能用了
    val blessingFunction3: (String) -> String = {
        val holiday = "New Year"
        "$it ,Happy $holiday"
    }
    println(blessingFunction3("rose"))

    //16、类型推断
    val blessingFunction4 = { name: String, year: Int ->
        val holiday = "New Year"
        "$name ,Happy $holiday. $year"
    }
    println(blessingFunction4("mahamu", 2027))

    //17、参数是函数的函数
    val getDiscountWords = { goodsName: String, hour: Int ->
        val currentYear = 2027
        "${currentYear}年,双十一${goodsName}促销倒计时：$hour 小时"
    }
    showonBoard("卫生纸", getDiscountWords)

    //简写 同12    如果一个函数的lambda参数排在最后或者是唯一的参数，圆括号可以省略
    showonBoard("卫生纸") { goodsName: String, hour: Int ->
        val currentYear = 2027
        "${currentYear}年,双十一${goodsName}促销倒计时：$hour 小时"
    }

    //18、函数内联 inline   使用lambda的递归函数无法内联

    //19、函数引用   使用lambda表达式的地方，都可以使用函数引用
    showonBoard("卫生纸", ::getDiscountWords)

    //20、函数类型作为返回类型
    val getConfigDiscountWords = configDiscountWords()
    println(getConfigDiscountWords("鞋袜"))

    //21、闭包 lambda就是闭包
    //匿名函数能修改并应用定义在自己作用域之外的变量，匿名函数引用着自身函数里的变量
    // 能接受函数或者返回函数的函数又叫高级函数

}

fun configDiscountWords(): (String) -> String {
    val currentYear = 2027
    var hour = (1..24).shuffled().last()

    return { goodsName: String ->
        hour += 20
        "${currentYear}年,双十一${goodsName}促销倒计时：$hour 小时"
    }
}


private fun showonBoard(goodsName: String, showDiscount: (String, Int) -> String) {
    val hour = (1..24).shuffled().last()
    print(showDiscount(goodsName, hour))
}

private fun getDiscountWords(goodsName: String, hour: Int): String {
    val currentYear = 2027
    return "${currentYear}年,双十一${goodsName}促销倒计时：$hour 小时"
}